﻿using Api.Shared.Model;
using Api.Shared.Model.Yanji;
using Microsoft.Extensions.Logging;
using S7.Net;
using System.Reflection;

namespace Api.Shared.MyPlc.S7
{
    public class S7ConnServiceImpl : IS7ConnService
    {
        public S7ConnServiceImpl(ILogger<S7ConnServiceImpl> logger, ApiData apiData, Db93Alarm db93Alarm, Db95DeviceHis db95DeviceHis)
        {
            this.logger = logger;
            this.apiData = apiData;
            this.db93Alarm = db93Alarm;
            this.db95DeviceHis = db95DeviceHis;
        }

        private static readonly object lockObj = new object(); // 创建一个对象作为锁
        private bool myIsConnected = false;
        private int errorTimes = 0;
        public bool MyIsConnected
        {
            get => myIsConnected;
            set => myIsConnected = value;
        }
        // 将 s7Plc 字段声明为可空类型
        private Plc? s7Plc = null;
        // 修改 S7Plc 属性的返回类型，确保与接口 IS7ConnService 的签名一致（非可空类型）。
        public Plc S7Plc => s7Plc!;

        private CancellationTokenSource cts = new();
        private readonly ILogger<S7ConnServiceImpl> logger;
        private ApiData apiData;
        private Db93Alarm db93Alarm;
        private Db95DeviceHis db95DeviceHis;

        public void ConnPlc(string myIp)
        {
            Task.Factory.StartNew(
                async () =>
                {
                    while (!cts.IsCancellationRequested)
                    {
                        if (s7Plc == null || !MyIsConnected)
                        {
                            try
                            {
                                s7Plc = new Plc(CpuType.S71200, myIp, 0, 1);
                                s7Plc.Open();
                                s7Plc.ReadTimeout = 620;
                                s7Plc.WriteTimeout = 620;
                                //ctsRead1 = new();
                                //ctsRead2 = new();
                                MyIsConnected = s7Plc.IsConnected;
                                if (MyIsConnected)
                                {
                                    logger.LogInformation("PlcSucessConn!");
                                }
                            }
                            catch (Exception ex)
                            {
                                errorTimes++;
                                s7Plc?.Close();
                                s7Plc = null;
                                MyIsConnected = false;
                                //logger.LogError(ex.Message);
                                // 替换以下两处 LogError 调用，使用一致的消息模板并通过参数传递变量

                                // 原始代码：
                                // logger.LogError(ex.Message);
                                // logger.LogError("ErrorsTime:" + errorTimes);

                                // 修正后：
                                logger.LogError("Plc连接异常: {ErrorMessage}", ex.Message);
                                logger.LogError("ErrorsTime: {ErrorTimes}", errorTimes);

                                // 另一处：
                                // logger.LogError($"读取时发生错误:{ex.Message}");
                                // logger.LogError($"读取时发生错误次数:{errorTimes}");

                                // 修正后：
                                //logger.LogError("读取时发生错误: {ErrorMessage}", ex.Message);
                                //logger.LogError("读取时发生错误次数: {ErrorTimes}", errorTimes);
                                await Task.Delay(2000);
                            }
                        }
                        else if (MyIsConnected)
                        {
                            try
                            {
                                MyIsConnected = s7Plc.IsConnected;
                                await Task.Delay(200);
                                errorTimes = 0;
                                //心跳
                                await s7Plc.WriteBitAsync(DataType.DataBlock, 61, 1, 2, true);
                                var dataTemp = await s7Plc.ReadClassAsync<ApiData>(60, 0);
                                var alarm = await s7Plc.ReadClassAsync<Db93Alarm>(93, 0);

                                var tempDb95DeviceHis = await S7Plc.ReadClassAsync<Db95DeviceHis>(95, 0);

                                lock (lockObj)
                                {
                                    //dbData.Str_S = dbDataTemp.Str_S.Trim();
                                    //dbData.Str_R = dbDataTemp.Str_R.Trim();
                                    //dbData.AutoStatus = dbDataTemp.AutoStatus;
                                    //dbData.DataSend = dbDataTemp.DataSend;
                                    //dbData.SendCharIsNotNull = dbDataTemp.SendCharIsNotNull;
                                    //dbData.ReciveError = dbDataTemp.ReciveError;
                                    //dbData.RobComplete = dbDataTemp.RobComplete;
                                    if (dataTemp != null)
                                    {
                                        CopyProperties(dataTemp, apiData);

                                    }
                                    if (alarm != null)
                                    {
                                        CopyProperties(alarm, db93Alarm);
                                    }
                                    if (tempDb95DeviceHis != null)
                                    {
                                        CopyProperties(tempDb95DeviceHis, db95DeviceHis);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                errorTimes++;
                                await Task.Delay(2000);

                                logger.LogError("读取时发生错误: {ErrorMessage}", ex.Message);
                                logger.LogError("读取时发生错误次数: {ErrorTimes}", errorTimes);
                                s7Plc.Close();
                                MyIsConnected = false;
                                s7Plc = null;
                            }
                        }
                    }
                },
                cts.Token,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Default
            );
        }


        /// <summary>
        /// 反射复制属性值
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void CopyProperties(object source, object destination)
        {
            if (source == null || destination == null)
            {
                throw new ArgumentNullException("Either source or destination is null.");
            }

            Type sourceType = source.GetType();
            Type targetType = destination.GetType();

            foreach (PropertyInfo sourceProperty in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                PropertyInfo? targetProperty = targetType.GetProperty(sourceProperty.Name);
                if (targetProperty != null && targetProperty.CanWrite && sourceProperty.PropertyType == targetProperty.PropertyType)
                {
                    targetProperty.SetValue(destination, sourceProperty.GetValue(source));
                }
            }
        }

        public void ConnPlc(string myIp, int dbNum, int startByte)
        {
            return;
        }
    }
}
